#include "Precompile.h"
#include "DX11Texture2D.h"
#include "DX11RenderSystem.h"

namespace Graphics{
	DX11Texture2D::DX11Texture2D(std::string &filename, ShaderResourceSlot slot, RenderContext* handle):m_texture(NULL),Texture2D(filename,slot,handle){
		// Load textures
		Utility::ImageDescriptionPtr imageDesc = Utility::ImageLoader::loadImage(filename);

		D3D11_SUBRESOURCE_DATA subResources;
		subResources.pSysMem = imageDesc->m_data;
		subResources.SysMemPitch = imageDesc->m_dataPitch;
		subResources.SysMemSlicePitch = 0;

		D3D11_TEXTURE2D_DESC tex2dDesc;
		ZeroMemory(&tex2dDesc,sizeof(D3D11_TEXTURE2D_DESC));
		tex2dDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		tex2dDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		tex2dDesc.ArraySize = 1;
		tex2dDesc.MiscFlags = 0;
		tex2dDesc.MipLevels = 1;
		tex2dDesc.SampleDesc.Count = 1;
		tex2dDesc.Width = imageDesc->m_width;
		tex2dDesc.Height = imageDesc->m_height;

		// Create dx texture
		HRESULT hr;
		hr = handle->m_handle->CreateTexture2D(&tex2dDesc,&subResources,&m_texSource);
		if(FAILED(hr)){
			LOG_ERROR("Failed in creating texture array.");
			assert(0);
			return;
		}

		D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
		srvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = 1;
		srvDesc.Texture2D.MostDetailedMip = 0;

		hr = handle->m_handle->CreateShaderResourceView(m_texSource,&srvDesc,&m_texture);
		if(FAILED(hr)){
			LOG_ERROR("Failed in creating shader resource view.");
			assert(0);
		}
	}

	DX11Texture2D::DX11Texture2D(int width, int height, int multisample, ShaderResourceSlot slot, TextureFormat format, RenderContext* handle):Texture2D(width,height,multisample,slot,format,handle){
		// Find multisample capabilities
		UINT SampleCount = multisample;
		m_qualityLevels = 0;
		if(SampleCount > 1 && FAILED(handle->m_handle->CheckMultisampleQualityLevels(getFormat(),SampleCount,&m_qualityLevels))){
			// Error handling
			LOG_ERROR("DX11RenderSystem::resetRenderSystem - Failed to check multisampling.");
			assert(0);
		}

		// Create the render target texture
		D3D11_TEXTURE2D_DESC desc;
		ZeroMemory( &desc, sizeof(desc) );
		desc.Width = width;
		desc.Height = height;
		desc.MipLevels = 1;
		desc.ArraySize = 1;
		desc.Format = getFormat();
		desc.SampleDesc.Count = SampleCount;
		desc.SampleDesc.Quality = m_qualityLevels-1;
		desc.Usage = D3D11_USAGE_DEFAULT;
		desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;

		HRESULT hr;
		hr = handle->m_handle->CreateTexture2D(&desc, NULL, &m_texSource);
		if(FAILED(hr)){
			LOG_ERROR("Failed in creating empty texture.");
			assert(0);
		}

		// Create the shader-resource view
		D3D11_SHADER_RESOURCE_VIEW_DESC srDesc;
		srDesc.Format = desc.Format;
		if(SampleCount > 1)
			srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
		else
			srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		srDesc.Texture2D.MostDetailedMip = 0;
		srDesc.Texture2D.MipLevels = 1;

		hr = handle->m_handle->CreateShaderResourceView( m_texSource, &srDesc, &m_texture );
		if(FAILED(hr)){
			LOG_ERROR("Failed in creating shader resource view.");
			assert(0);
		}
	}

	DX11Texture2D::DX11Texture2D(ID3D11Texture2D* texture,int width, int height, int multisample, TextureFormat format, RenderContext* handle):Texture2D(width,height,multisample,SRS_NONE,format,handle){
		m_texSource = texture;
		m_texture = NULL;
	}

	DX11Texture2D::~DX11Texture2D(){
		if(m_texture){
			if(m_texture->Release() != 0){
				LOG_ERROR("Referens count fault.");
				assert(0);
			}
		}
		if(m_texSource)
			m_texSource->Release();
	}

	void DX11Texture2D::setTexture(RenderContext* context){
		DX11RenderContext* ctx = (DX11RenderContext*)context;

		ctx->m_context->PSSetShaderResources(UINT(m_slot),1,&m_texture);
	}

	DXGI_FORMAT DX11Texture2D::getFormat(){
		switch(m_format){
		case TF_B8G8R8A8_UNORM:
			return DXGI_FORMAT_B8G8R8A8_UNORM;
		case TF_R32_FLOAT:
			return DXGI_FORMAT_R32_FLOAT;
		case TF_R8G8B8A8_UNORM:
			return DXGI_FORMAT_R8G8B8A8_UNORM;
		default:
			return DXGI_FORMAT_B8G8R8A8_UNORM;
		}
	}
}